/***************************************************************************
 *   Copyright (C) 2010 by programmeboy                                    *
 *   programmeboy@gmail.com                                                *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.                                        *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             * 
 ***************************************************************************/


#include <ntifs.h>
#include "common.h"
#include "fsd.h"

const WCHAR* gFileSystem[] = {
    L"\\FileSystem\\Ntfs",
    L"\\FileSystem\\Fat",
    L"\\FileSystem\\Cdfs"
};

NTSTATUS
QueryFsdHookInfo(
    OUT PVOID Buffer,
    IN ULONG BufferLength,
    OUT PULONG Length 
)
{
    ULONG FsIndex;
    PFSD_HOOK_ITEM FsdHookInfo = (PFSD_HOOK_ITEM)Buffer;
    ULONG TotalLength = 0;
    NTSTATUS ntStatus;

    if (ARGUMENT_PRESENT(Length)){
        *Length = 0;
    }

    try{
        for (FsIndex = 0; FsIndex < array_capacity(gFileSystem); FsIndex++){
            UNICODE_STRING uniFilesystem;
            PVOID Object;

            RtlInitUnicodeString(&uniFilesystem, gFileSystem[FsIndex]);
        
            //
            //  TODO support win7
            //
        
            Object = ObReferenceObjectByName( &uniFilesystem, 
                                              OBJ_CASE_INSENSITIVE, 
                                              0L, 
                                              0, 
                                              IoDriverObjectType,
                                              KernelMode,
                                              NULL,
                                              &Object);
            if (Object){
                FsdHookInfo = (ULONG)Buffer + TotalLength;
                TotalLength += sizeof(FSD_HOOK_ITEM);
                if (TotalLength > BufferLength){
                    ntStatus = STATUS_INFO_LENGTH_MISMATCH;
                    if (!ARGUMENT_PRESENT(Length)){
                        RtlFreeUnicodeString(&uniFilesystem);
                        leave;
                    }
                }else{
                    
                    //
                    //  copy fsd info.
                    //
                    
                    FsdHookInfo->Index = FsIndex;
                    RtlCopyMemory(FsdHookInfo->MjFunction, ((PDRIVER_OBJECT)Object)->MajorFunction,
                        sizeof(FsdHookInfo->MjFunction));
                }

                //
                // Set output buffer length.
                //
            
                if (ARGUMENT_PRESENT(Length)){
                    *Length = TotalLength;
                }

                ObDereferenceObject(Object);
            }

            RtlFreeUnicodeString(&uniFilesystem);
        }
    }except(EXCEPTION_EXECUTE_HANDLER){
        ntStatus = GetExceptionCode();
    }

    return ntStatus;
}